package helper

import (
	"fmt"
	"time"

	"golang-blog/infrastructure/log"
	"net/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
)

func SetHttpMsgResp(c *gin.Context, code int, msg string) {
	c.Data(http.StatusOK, "application/json", HttpRespErrorMarshal(code, msg))
}
func SetHttpDataResp(c *gin.Context, data string) {
	c.Data(http.StatusOK, "application/json", HttpRespDataMarshal(data))
}

func CORS() gin.HandlerFunc {
	return func(context *gin.Context) {
		context.Writer.Header().Add("Access-Control-Allow-Origin", "*")
		context.Writer.Header().Set("Access-Control-Max-Age", "86400")
		context.Writer.Header().Set("Access-Control-Allow-Methods", "HEAD, POST, GET, OPTIONS, PUT, DELETE")
		context.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, AuthorizationToken")
		context.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
		context.Writer.Header().Set("Access-Control-Allow-Credentials", "true")

		if context.Request.Method == "OPTIONS" || context.Request.Method == "HEAD" {
			context.AbortWithStatus(200)
		} else {
			context.Next()
		}
	}
}
func Auth() gin.HandlerFunc {

	return func(ctx *gin.Context) {
		if os.Getenv("GIN_MODE") == "release" {
			jwtToken := ctx.Request.Header.Get("token")
			if err := JwtAuth(string(jwtToken), "jzsg"); err != nil {
				SetHttpMsgResp(ctx, HttpCodeAuthFail, "jwt auth fail")
				ctx.Abort()
				return
			}
		} else {
			// log.Warn("@@@@ 当前运行程序为debug模式, 无鉴权功能！软件发布后请配置环境变量： GIN_MODE=release ！@@@@")
		}

		ctx.Next()
	}
}

// Logger is the logrus logger handler
func myLogger(logger logrus.FieldLogger, notLogged ...string) gin.HandlerFunc {
	hostname, err := os.Hostname()
	if err != nil {
		hostname = "unknow"
	}

	var skip map[string]struct{}

	if length := len(notLogged); length > 0 {
		skip = make(map[string]struct{}, length)

		for _, p := range notLogged {
			skip[p] = struct{}{}
		}
	}

	return func(c *gin.Context) {
		// other handler can change c.Path so:
		path := c.Request.URL.Path
		start := time.Now()
		c.Next()
		stop := time.Since(start)
		// latency := int(math.Ceil(float64(stop.Nanoseconds()) / 1000000.0))
		latency := float64(stop.Nanoseconds()) / 1000000.0
		statusCode := c.Writer.Status()
		clientIP := c.ClientIP()
		clientUserAgent := c.Request.UserAgent()
		referer := c.Request.Referer()
		dataLength := c.Writer.Size()
		if dataLength < 0 {
			dataLength = 0
		}

		if _, ok := skip[path]; ok {
			return
		}

		entry := logger.WithFields(logrus.Fields{
			"hostname":   hostname,
			"statusCode": statusCode,
			"latency":    latency, // time to process
			"clientIP":   clientIP,
			"method":     c.Request.Method,
			"path":       path,
			"referer":    referer,
			"dataLength": dataLength,
			"userAgent":  clientUserAgent,
		})

		if len(c.Errors) > 0 {
			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
		} else {
			msg := fmt.Sprintf("ClIENT %s | %s | %s | %d (%vms)", clientIP, c.Request.Method, path, statusCode, latency)
			if statusCode >= http.StatusInternalServerError {
				logger.Error(msg)
			} else if statusCode >= http.StatusBadRequest {
				logger.Warn(msg)
			} else {
				logger.Info(msg)
			}
		}
	}
}

func Logger() gin.HandlerFunc {
	return myLogger(log.Logger(), "/qid/v1/ping", "/vc/v1/ping")
}
